/*
实现异步日志缓冲区
 */
#ifndef __M_BUF_H__
#define __M_BUF_H__
#include "util.hpp"
#include <vector>
#include <cassert>

namespace xglog
{
#define DEFAULT_BUFFER_SIZE (1 * 1024 * 1024)    // 缓冲区默认大小
#define THRESHOLD_BUFFER_SIZE (8 * 1024 * 1024)  // 阈值
#define INCREAMENT_BUFFER_SIZE (1 * 1024 * 1024) // 增量
  class Buffer
  {
  public:
    Buffer() : _buffer(DEFAULT_BUFFER_SIZE), _reader_idx(0), _writer_idx(0)
    {
    }
    // 向缓冲区写入数据
    void push(const char *data, size_t len)
    {
      // 缓冲区剩余空间不足的情况：1.扩容 2.阻塞等待
      // 一.固定大小
      // if (len > writeAbleSize())
      //   return;
      // 二.进行动态扩容
      ensureEnoughSize(len);
      // 1.将数据直接拷贝进缓冲区
      std::copy(data, data + len, &_buffer[_writer_idx]);
      // 2.将当前位置向后移
      moveWriter(len);
    }
    // 返回可写长度
    size_t writeAbleSize()
    {
      // 对于扩容思路来说，不需要这个接口
      // 这个接口只在固定大小使用
      return (_buffer.size() - _writer_idx);
    }
    // 返回可读数据的起始地址
    const char *begin()
    {
      return &_buffer[_reader_idx];
    }
    // 返回可读数据的长度
    size_t readAbleSize()
    {
      // 这里要明白，是两个缓冲区，写满了每次都会交换缓冲区，也就不存在循环一说
      return (_writer_idx - _reader_idx);
    }
    void moveReader(size_t len)
    {
      assert(len <= readAbleSize());
      _reader_idx += len;
    }
    // 重置读写位置，初始化缓冲区
    void reset()
    {
      _writer_idx = 0;
      _reader_idx = 0;
    }
    // 交换空间，缓冲区之间的交换
    void swap(Buffer &buffer)
    {
      _buffer.swap(buffer._buffer);
      std::swap(_reader_idx, buffer._reader_idx);
      std::swap(_writer_idx, buffer._writer_idx);
    }
    // 判断缓冲区是否为空
    bool empty()
    {
      return (_reader_idx == _writer_idx);
    }

  private:
    // 对空间进行扩容
    void ensureEnoughSize(size_t len)
    {
      if (len <= writeAbleSize())
        return;
      size_t new_size = 0;
      if (_buffer.size() < THRESHOLD_BUFFER_SIZE)
      {
        new_size = _buffer.size() * 2 + len;
      }
      else
      {
        new_size = _buffer.size() + INCREAMENT_BUFFER_SIZE + len;
      }
      _buffer.resize(new_size);
    }
    // 对读写指针进行向后偏移操作
    void moveWriter(size_t len)
    {
      assert(len + _writer_idx < _buffer.size());
      _writer_idx += len;
    }

  private:
    std::vector<char> _buffer;
    size_t _reader_idx; // 可读数据的下标
    size_t _writer_idx; // 写数据的下标
  };
}
#endif